#encoding: utf-8

from exts import db
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash

# 权限定义
class CMSPermission(object):
    # 255的二进制方式来表示 1111 1111
    ALL_PERMISSION = 0b11111111
    # 1.访问者权限
    VISITOR = 0b00000001
    # 2.管理帖子权限
    POSTER = 0b00000010
    # 3.管理评论权限
    COMMENTER = 0b00000100
    # 4.管理模块权限
    BOARDER = 0b00001000
    # 5.管理前台用户权限
    FRONTUSER = 0b00010000
    # 6.管理后台用户的权限
    CMSUSER = 0b00100000
    # 7.后台管理员权限
    ADMINER = 0b01000000

# 角色和用户的关系表
cms_role_user = db.Table(
    'cms_role_user',
    db.Column('cms_role_id', db.Integer, db.ForeignKey('cms_role.id'), primary_key=True),
    db.Column('cms_user_id', db.Integer, db.ForeignKey('cms_user.id'), primary_key=True),
)

# 定义角色
class CMSRole(db.Model):
    __tablename__ = 'cms_role'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(50), nullable=False)
    desc = db.Column(db.String(200),nullable=True)
    create_time = db.Column(db.DateTime, default=datetime.now)
    permissions = db.Column(db.Integer, default=CMSPermission.VISITOR)

    users = db.relationship('CMSUser', secondary=cms_role_user, backref='roles')  # 反向引用


# 用户定义
class CMSUser(db.Model):
    __tablename__ = 'cms_user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(50), nullable=False, comment='用户名')
    useraccount = db.Column(db.String(50), nullable=False, unique=True, comment='帐号')

    # 密码：对外的字段名叫做password，对内的字段名叫做_password
    _password = db.Column(db.String(100), nullable=False)

    email = db.Column(db.String(50), nullable=False, unique=True,comment='邮箱')
    mobile = db.Column(db.String(15), nullable=False, unique=True,comment='手机号')
    join_time = db.Column(db.DateTime, default=datetime.now, comment='加入时间')
    create_by = db.Column(db.String(30), nullable=False, comment='创建人')
    update_by = db.Column(db.String(30), nullable=False, comment='更新人')
    create_at = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='创建时间')
    update_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment='更新时间')
    status = db.Column(db.SmallInteger, nullable=False, default=1, comment='启用状态')
    isDel = db.Column(db.SmallInteger, nullable=False, default=0, comment='是否删除')

    def __init__(self, username, useraccount, password, email, mobile, create_by, update_by):
        self.username = username
        self.useraccount = useraccount
        self.password = password
        self.email = email
        self.mobile = mobile
        self.create_by = create_by
        self.update_by = update_by

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, raw_password):
        self._password = generate_password_hash(raw_password)

    def check_password(self, raw_password):
        result = check_password_hash(self.password, raw_password)
        return result

    # 获取权限
    @property
    def permissions(self):
        if not self.roles:
            return 0
        all_permissions = 0
        for role in self.roles:
            permissions = role.permissions
            all_permissions |= permissions
        return all_permissions

    # 判断权限
    def has_permission(self, permission):
        # all_permissions = self.permissions
        # result= all_permissions & permission == permission
        # return result
        return self.permissions & permission == permission

    @property
    def is_developer(self):
        return self.has_permission(CMSPermission.ALL_PERMISSION)


# 用例分组
class CaseGroup(db.Model):
    __tablename__ = 'case_group'
    group_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    group_name = db.Column(db.String(50), nullable=False, unique=True, comment='组名称')
    group_code = db.Column(db.String(20), nullable=False, unique=True, comment='组code，用来生成第一次关联用例的用例编号')
    ext = db.Column(db.String(50), nullable=True, comment='扩展字段')
    create_by = db.Column(db.String(30), nullable=False, comment='创建人')
    update_by = db.Column(db.String(30), nullable=False, comment='更新人')
    create_at = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='创建时间')
    update_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment='更新时间')
    status = db.Column(db.SmallInteger, nullable=False, default=1, comment='启用状态')
    isDel = db.Column(db.SmallInteger, nullable=False, default=0, comment='是否删除')

# 用例和计划关系表
case_plan_relation = db.Table(
    'case_plan_relation',
    db.Column('cp_plan_id', db.Integer, db.ForeignKey('case_plan.plan_id'), primary_key=True),
    db.Column('cp_case_id', db.Integer, db.ForeignKey('case_manage.case_id'), primary_key=True),
)

# 用例管理
class CaseManage(db.Model):
    __tablename__ = 'case_manage'
    case_id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
    case_name = db.Column(db.String(50), nullable=False, unique=True, comment='用例名称')
    case_sign = db.Column(db.String(50), nullable=False, unique=True, comment='用例编号')
    case_path = db.Column(db.String(1000), nullable=False, comment='url')
    case_parm = db.Column(db.String(2000), nullable=True, default='', comment='参数')
    request_method = db.Column(db.String(8), nullable=False, comment='http请求方法')
    expect_res = db.Column(db.String(100), nullable=False, comment='预期结果')
    headers = db.Column(db.String(3000), nullable=True, default='', comment='http请求头信息')
    remark = db.Column(db.String(1000), nullable=True, default='', comment='备注')

    create_by = db.Column(db.String(30), nullable=False, comment='创建人')
    update_by = db.Column(db.String(30), nullable=False, comment='更新人')
    create_at = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='创建时间')
    update_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment='更新时间')
    status = db.Column(db.SmallInteger, nullable=False, default=1, comment='可执行状态，1-可执行，0-不可执行')
    isDel = db.Column(db.SmallInteger, nullable=False, default=0, comment='是否删除')

    group_id = db.Column('group_id', db.Integer, db.ForeignKey('case_group.group_id'))
    case_group = db.relationship('CaseGroup', backref='casemanage', single_parent=True)

# 用例计划管理
class CasePlan(db.Model):
    __tablename__ = 'case_plan'
    plan_id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
    plan_name = db.Column(db.String(50), nullable=False, unique=True, comment='计划名称')
    case_run_way = db.Column(db.SmallInteger, nullable=False, default=1, comment='关联用例的执行方式：0-循环执行，1-执行1次，2-执行2次，依次类推')
    plan_group = db.Column(db.Integer, nullable=False, default=-1, comment='关联的分组，默认-1为没设置')
    delay_time = db.Column(db.Integer, nullable=False, default=300, comment='用例执行一次后，等待下次执行的时间，单位为秒')
    case_run_way_01 = db.Column(db.String(2), nullable=False, default='次', comment='用例执行方式的单位，次-按次数执行，分钟-按指定的时间执行')
    create_by = db.Column(db.String(30), nullable=False, comment='创建人')
    update_by = db.Column(db.String(30), nullable=False, comment='更新人')
    create_at = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='创建时间')
    update_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment='更新时间')
    status = db.Column(db.SmallInteger, nullable=False, default=0, comment='计划执行状态，1-开启，0-关闭')
    isDel = db.Column(db.SmallInteger, nullable=False, default=0, comment='是否删除')

    cases = db.relationship('CaseManage', secondary=case_plan_relation, backref='casePlan')  # 反向引用

# 用例执行结果
class CaseRunRes(db.Model):
    __tablename__ = 'case_run_res'
    res_id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
    wheel_no = db.Column(db.String(35), nullable=False, comment='执行轮次编号')
    res_case_id = db.Column(db.Integer, nullable=False, default=-1, comment='用例id')
    res_case_sign = db.Column(db.String(50), nullable=False, default='system', comment='用例编号')
    res_group_id = db.Column(db.Integer, nullable=False, default=-1, comment='分组id')
    res_plan_id = db.Column(db.Integer, nullable=False, default=-1, comment='计划id')
    res_case_path = db.Column(db.String(1000), nullable=False, comment='url')
    res_case_parm = db.Column(db.String(2000), nullable=True, default='', comment='参数')
    res_case_header = db.Column(db.String(3000), nullable=True, default='', comment='请求headers')
    res_status = db.Column(db.SmallInteger, nullable=False, default=0, comment='用例执行结果：0-未执行，1-执行和断言都成功，9-执行成功，断言失败，4-执行异常，2-用例传参为空，3-用例传参不是CaseManage')
    res_http_code = db.Column(db.SmallInteger, comment='http响应码')
    expect_res = db.Column(db.String(100), comment='预期结果')
    res_detail = db.Column(db.String(5000), comment='执行结果')
    cost_time = db.Column(db.Integer,nullable=False, default=0, comment='用例花费时间，单位：毫秒')
    run_type = db.Column(db.SmallInteger, comment='执行类型：1-调度循环执行，2-调度指定次数或时间执行，3-调试')
    create_by = db.Column(db.String(30), nullable=False, default='系统更新', comment='创建人')
    update_by = db.Column(db.String(30), nullable=False, default='系统更新', comment='更新人')
    create_at = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='创建时间')
    update_at = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment='更新时间')


# 用例执行结果统计
class CaseRunResSummary(db.Model):
    __tablename__ = 'case_run_res_summary'
    s_id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
    s_plan_id = db.Column(db.Integer, nullable=False, default=-1, comment='计划id')
    s_plan_name = db.Column(db.String(50), nullable=False, comment='计划名称')
    total_count = db.Column(db.SmallInteger, nullable=False, default=0, comment='成功用例数')
    succ_count = db.Column(db.SmallInteger, nullable=False, default=0, comment='成功用例数')
    fail_count = db.Column(db.SmallInteger, nullable=False, default=0, comment='失败用例数')
    other_count = db.Column(db.SmallInteger, nullable=False, default=0, comment='未执行用例数')
    run_type = db.Column(db.SmallInteger, comment='执行类型：1-调度循环执行，2-调度指定次数或时间执行，3-调试')
    create_at = db.Column(db.DateTime, nullable=False, default=datetime.now, comment='创建时间')
